// http://www.flickr.com/services/api/response.json.html
var flickr = {
	api: 'http://api.flickr.com/services/rest/?format=json&nojsoncallback=1',
	key: '459e62a3f2bcd299cd8fe8a58b8d1fb6',
	salt: '135678bbdb34a901',
	preloadImages: false,
	frob: null,
	credentials: {
		token: ti.data.get('token'),
		id: ti.data.get('id'),
		permission: 'read',
		name: ti.data.get('name'),
		save: function() {
			ti.data.set('name', this.name);
			ti.data.set('token', this.token);
			ti.data.set('id', this.id);
		},
		update: function(auth) {
			console.log('storing Flickr authentication: ' + JSON.stringify(auth));
			this.token = auth.token._content;
			this.permission = auth.perms._content;
			this.name = auth.user.fullname;
			this.id = auth.user.nsid;
			this.save();
		},
		clear: function() {
			this.token = null;
			this.id = null;
			this.name = null;
			ti.data.remove(['name','token','id']);
		}
	},
	visibleTo: 0,
	page: 'http://flickr.com/photo.gne?id=',
	xhr: null,
	get: {
		sizes: 'flickr.photos.getSizes',
		location: 'flickr.photos.geo.getLocation',
		exif: 'flickr.photos.getExif',
		frob: 'flickr.auth.getFrob',
		token: 'flickr.auth.getToken',
		photo: 'flickr.photos.getInfo',
		collection: 'flickr.collections.getTree',
		setPhotos: 'flickr.photosets.getPhotos',
		setInfo: 'flickr.photosets.getInfo',
		setList: 'flickr.photosets.getList',
		sizes: 'flickr.photos.getSizes'
	},
	url: function(methodName, id) {
		// generate API URL
		// http://www.flickr.com/services/api/
		var link = this.api
			+ '&api_key=' + this.key
			+ '&method=' + methodName;
		if (id) {
			if (/\.photos\./.test(methodName)) { link += '&photo_id=' + id; }
			else if (/\.collections\./.test(methodName)) { link += '&collection_id=' + id; }
			else if (/\.photosets\.get[PI]/.test(methodName)) {
				link += '&photoset_id=' + id;
				if (/getPhotos/.test(methodName)) {	link += '&extras=date_taken,geo,url_o';	}
				if (this.visibleTo) { link += '&privacy_filter=' + this.visibleTo; }
			}
			else if (/\.photosets.getList/.test(methodName)) {
				link += '&user_id=' + id;
			}
			else if (/getToken/.test(methodName)) { link += '&frob=' + id; }
		}
		return this.sign(link);
	},
	cancel: function() { if (this.xhr) { this.xhr.abort(); } },
	service: function(id, methodName, callback, jsonFn) {
		var url = this.url(methodName, id);
		var xhr = new XMLHttpRequest();
		xhr.onreadystatechange = function() {
			if (xhr.readyState == 4) {
				var r = new responseObject(xhr, url);
				if (xhr.status == 200) {
					try {
						r.json = JSON.parse(xhr.responseText);
						if (jsonFn) { r.json = jsonFn(r.json); }
					} catch (e) {
						r.status.success = false;
						r.status.message = e.description || e.message;
						console.log(JSON.stringify(r));
					}
				} else {
					r.status.success = false;
					r.status.message = r.status.message || 'invalid HTML response';
				}
				callback(r);
			}
		}
		console.log('loading ' + url);
		xhr.open('GET', url, true);
		xhr.send();
	},
	parseExif: function(data) {
		if (!data || !data.length) { return null; }
		var allow = /(IFD0|ExifIFD|XMP-tiff|XMP-aux)/;
		var exif = new Object();
		for (var i = 0; i < data.length; i++) {
			if (allow.test(data[i].tagspace)) {
				exif[data[i].label] = data[i].raw._content;
			}
		}
		return exif;
	},
	getJsonpCallback: function(methodName, id) {
		var name = methodName.substr(methodName.lastIndexOf('.') + 1);
		if (id) { name += id.replace(/\W/, ''); }
		return name;
	},
	sign: function(url, jsonpCallback) {
		// http://www.flickr.com/services/api/auth.spec.html
		var re = /[\?&]([^&=\?]+=[^&=]+)/g;
		var params = [];
		var match;
		
		if (this.credentials.token) { url += '&auth_token=' + this.credentials.token; }
		while (match = re.exec(url)) { params.push(match[1].replace(/,/g,'�')); }
		params.sort();
		return url + '&api_sig=' + hex_md5(this.salt
			+ params.toString().replace(/[=,]/g, '').replace(/�/g,','));
	},
	getToken: function(callback) {
		flickr.service(flickr.frob, flickr.get.token, function(r) {
			flickr.credentials.update(r.json.auth);
			callback(true);
		});
	},
	getLoginUrl: function(callback) {
		flickr.service(null, flickr.get.frob, function(r) {
			flickr.frob = r.json.frob._content;
			var url = 'http://flickr.com/services/auth/'
				+ '?api_key=' + flickr.key
				+ '&perms=' + flickr.credentials.permission
				+ '&frob=' + flickr.frob;
			callback(flickr.sign(url));
		});
	},
	getCollection: function(id, callback) {
		if (/\D/.test(id)) { id = ti.flickrDataID + '-' + id; }
		flickr.service(id, flickr.get.collection, function(r) {
			callback(new collectionObject(r.collections.collection[0]));
		});
	},
	getSetList: function(id, callback) {
		if (!id) { id = flickr.credentials.id; }
		flickr.service(id, flickr.get.setList, callback, function(json) {
			var list = [];
			for (var i = 0; i < json.photosets.photoset.length; i++) {
				if (json.photosets.photoset[i].photos) {
					list.push(new setObject(null, json.photosets.photoset[i]));
				}
			}
			return list;
		});
	},
	getSet: function(id, callback) {
		if (/\D/.test(id)) {
			// match non-numeric name to ID
			if (ti.sets[id]) {
				// use cached set ID
				flickr.getSet(ti.sets[id].id, callback);
			} else {
				// load collection to find set ID
				flickr.getCollection(ti.collection, function(c) {
					var match = c.findSet(id);
					if (match) {
						flickr.getSet(match, callback);
					} else {
						ti.alert('Unable to find set ' + id);
					}
				});
			}
		} else {
			flickr.service(id, flickr.get.setPhotos, function(r) {
				var photos = r.json.photoset;
				flickr.service(id, flickr.get.setInfo, function(r) {
					callback(new setObject(photos, r.json.photoset));
				});
			});
		}
	},
	getPhoto: function(id, callback) {
		flickr.service(id, flickr.get.photo, function(r) {
			callback(new simplePhotoObject(r.json.photo));
		});
	}
};

function responseObject(xhr, url) {
	this.status = {
		'success': true,
		'message': xhr.statusText,
		'code': xhr.status
	},
	this.url = url;
	this.json =  null;
}

function collectionObject(tree) {
	// object representing a Flickr collection
	var _c = this;
	this.id = tree.id;
	this.title = ti.format.text(tree.title);
	this.collections = [];
	this.sets = [];
	this.findSet = function(url) {
		// search recursively for the set with the url created by setInfoObject.url()
		for (var i in _c.sets) {
			if (_c.sets[i].url() == url) { return _c.sets[i].id; }
		}
		for (var i in _c.collections) {
			var id = _c.collections[i].findSet(url);
			if (id) { return id; }
		}
		return null;
	}
	parseCollections();
	parseSets();

	function parseCollections() {
		for (var i in tree.collection) {
			_c.collections.push(new collectionObject(tree.collection[i]));
		}
	}
	
	function parseSets() {
		for (var i in tree.set) { _c.sets.push(new setInfoObject(tree.set[i])); }
	}
	
	function setInfoObject(info) {
		var _s = this;
		this.id = info.id;
		this.title = ti.format.text(info.title);
		this.description = ti.format.text(info.description);
		this.url = function() {
			// convert the title to URL friendly text
			return _s.title
				.replace(/\W/g, '-')
				.replace(/\-{2,}/, '-')
				.replace(/\-$/, '')
				.toLowerCase();
		}
		this.link = function() {
			return '<a href="/' + _s.url() + '">' + _s.title + '</a>';
		}
	}
}


// http://www.flickr.com/services/api/flickr.photosets.getInfo.html
// http://www.flickr.com/services/api/flickr.photosets.getPhotos.html
function setObject(set, info) {
	// object representing a Flickr set
	var _s = this;
	this.id = info.id;
	this.title = ti.format.text(info.title._content);
	this.description = ti.format.text(info.description._content);
	this.total = info.photos;
	this.photos = [];
	this.coverPhoto = null;
	
	if (set) { parsePhotos(); }

	function parsePhotos() {
		_s.total = set.total;
		for (var i = 0; i < set.photo.length; i++) {
			var p = new photoObject(set.photo[i]);
			_s.photos.push(p);
			if (set.photo[i].isprimary) { _s.coverPhoto = p; }
		}
	}
	function photoObject(api) {
		// object representing a Flickr photo in a set
		var _p = this;
		var _id = api.id;
		var _secret = api.secret;
		var _originalUrl = api.url_o;
		var _farmId = api.farm;
		var _serverId = api.server;
		this.image = (flickr.preloadImages) ? new Image() : null;
		this.title = api.title;
		this.description = null;
		this.pageUrl = null;
		this.mapUrl = 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q='
			+ api.latitude + ',' + api.longitude + '&t=h&z=15';;
		this.thumbnail = null;
		this.dateTaken = ti.format.date(api.datetaken);
		this.hidden = false;
		this.loaded = false;
		this.url = function(size) {
			// http://www.flickr.com/services/api/misc.urls.html
			// http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}.jpg
			if (size == 'o') { return _originalUrl; }
			var suffix = (size == '-') ? '' : '_' + size;
			return 'http://farm' + _farmId + '.static.flickr.com/'
				 + _serverId + '/' + _id + '_' + _secret + suffix + '.jpg';
		}

		this.load = function(callback) {
			// load details from Flickr
			flickr.service(_id, flickr.get.photo, function(r) {
				var p = r.photo;
				_p.title = ti.format.text(p.title._content);
				_p.description = ti.format.text(p.description._content);
				_p.pageUrl = p.urls.url[0]._content;
				_p.dateTaken = ti.format.date(p.dates.taken);
				flickr.service(_id, flickr.get.sizes, function(r) {
					for (var i = r.sizes.size.length - 1; i >= 0; i--) {
						// record maximum size for both screen and window
						var size = r.sizes.size[i];
						if (checkSize(size, _s.screenWidth, enums.sizeFor.screen)
						 && checkSize(size, _s.windowWidth, enums.sizeFor.window)) { break; }
					}
					setupImage();
					_p.loaded = true;
					callback();
				});
			});
		}
		
		function setupImage() {
			// setting image object source triggers download to browser cache
			_p.image.src = _imageSize.url;
			_p.image.height = _imageSize.height;
			_p.image.width = _imageSize.width;
		}
		
		function checkSize(size, width, sizeEnum) {
			var s = _imageSize[sizeEnum];
			if (s.width != 0) {
				return true;
			} else if ((size.width * 1) + _s.gutterWidth <= width) {
				//ti.alert(sizeEnum + ' ' + size.width);
				s.url = size.source
				s.width = size.width * 1;
				s.height = size.height * 1;
				return true;
			} else {
				return false;
			}
		}
	}
}

function simplePhotoObject(api) {
	var _this = this;
	this.id = api.id;
	this.title = ti.format.text(api.title._content);
	this.description = ti.format.text(api.description._content);
	this.pageUrl = api.urls.url[0]._content;
	this.dateTaken = ti.format.date(api.dates.taken);
	this.secret = api.secret;
	this.farmId = api.farm;
	this.serverId = api.server;
	this.originalUrl = api.url_o;
	this.mapUrl = 'http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q='
		+ api.location.latitude + ',' + api.location.longitude + '&t=h&z=15';
}